using Net35.Xrm.Sdk.Client;
using Net35.Xrm.Sdk.Messages;
using Net35.Xrm.Sdk.Query;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
namespace Net35.Xrm.Sdk.Linq
{
	internal class QueryProvider : IQueryProvider
	{
		protected sealed class NavigationSource
		{
			public EntityReference Target
			{
				get;
				private set;
			}
			public Relationship Relationship
			{
				get;
				private set;
			}
			public NavigationSource(EntityReference target, Relationship relationship)
			{
				this.Target = target;
				this.Relationship = relationship;
			}
		}
		protected sealed class FilterExpressionWrapper
		{
			public FilterExpression Filter
			{
				get;
				private set;
			}
			public string Alias
			{
				get;
				private set;
			}
			public FilterExpressionWrapper(FilterExpression filter, string alias)
			{
				if (filter == null)
				{
					throw new ArgumentNullException("filter");
				}
				this.Filter = filter;
				this.Alias = alias;
			}
		}
		protected sealed class LinkLookup
		{
			public string ParameterName
			{
				get;
				private set;
			}
			public string Environment
			{
				get;
				private set;
			}
			public LinkEntity Link
			{
				get;
				private set;
			}
			public string SelectManyEnvironment
			{
				get;
				private set;
			}
			public LinkLookup(string parameterName, string environment, LinkEntity link) : this(parameterName, environment, link, null)
			{
			}
			public LinkLookup(string parameterName, string environment, LinkEntity link, string selectManyEnvironment)
			{
				this.ParameterName = parameterName;
				this.Environment = environment;
				this.Link = link;
				this.SelectManyEnvironment = selectManyEnvironment;
			}
		}
		protected sealed class Projection
		{
			public string MethodName
			{
				get;
				private set;
			}
			public LambdaExpression Expression
			{
				get;
				private set;
			}
			public Projection(string methodName, LambdaExpression expression)
			{
				this.MethodName = methodName;
				this.Expression = expression;
			}
		}
		protected sealed class EntityColumn
		{
			public string ParameterName
			{
				get;
				private set;
			}
			public string Column
			{
				get;
				private set;
			}
			public bool AllColumns
			{
				get;
				private set;
			}
			public EntityColumn()
			{
			}
			public EntityColumn(string parameterName, string column)
			{
				this.ParameterName = parameterName;
				this.Column = column;
			}
			public EntityColumn(string parameterName, bool allColumns)
			{
				this.ParameterName = parameterName;
				this.AllColumns = allColumns;
			}
		}
		private readonly OrganizationServiceContext _context;
		private static readonly IEnumerable<string> _followingRoot;
		private static readonly IEnumerable<string> _followingFirst;
		private static readonly IEnumerable<string> _followingTake;
		private static readonly IEnumerable<string> _followingSkip;
		private static readonly IEnumerable<string> _followingSelect;
		private static readonly IEnumerable<string> _followingOrderBy;
		private static readonly IEnumerable<string> _followingWhere;
		private static readonly IEnumerable<string> _followingJoin;
		private static readonly IEnumerable<string> _followingGroupJoin;
		private static readonly Dictionary<string, IEnumerable<string>> _followingMethodLookup;
		private static readonly string[] _supportedMethods;
		private static readonly string[] _validMethods;
		private static readonly string[] _validProperties;
		private static readonly Dictionary<ExpressionType, ConditionOperator> _conditionLookup;
		private static readonly Dictionary<ConditionOperator, ConditionOperator> _operatorNegationLookup;
		private static readonly Dictionary<ExpressionType, LogicalOperator> _booleanLookup;
		private static readonly Dictionary<LogicalOperator, LogicalOperator> _logicalOperatorNegationLookup;
		protected OrganizationServiceContext OrganizationServiceContext
		{
			get
			{
				return this._context;
			}
		}
		protected virtual int RetrievalUpperLimitWithoutPagingCookie
		{
			get
			{
				return 5000;
			}
		}
		public QueryProvider(OrganizationServiceContext context)
		{
			this._context = context;
		}
		private IQueryable CreateQuery(Type entityType)
		{
			this.CheckEntitySubclass(entityType);
			string nameForType = KnownProxyTypesProvider.GetInstance(true).GetNameForType(entityType);
			return this.CreateQueryInstance(entityType, new object[]
			{
				this,
				nameForType
			});
		}
		private IQueryable<TElement> CreateQuery<TElement>(Expression expression)
		{
			return new Query<TElement>(this, expression);
		}
		private IQueryable CreateQuery(Expression expression)
		{
			Type elementType = expression.Type.GetGenericArguments()[0];
			return this.CreateQueryInstance(elementType, new object[]
			{
				this,
				expression
			});
		}
		IQueryable<TElement> IQueryProvider.CreateQuery<TElement>(Expression expression)
		{
			ClientExceptionHelper.ThrowIfNull(expression, "expression");
			return this.CreateQuery<TElement>(expression);
		}
		IQueryable IQueryProvider.CreateQuery(Expression expression)
		{
			ClientExceptionHelper.ThrowIfNull(expression, "expression");
			return this.CreateQuery(expression);
		}
		TResult IQueryProvider.Execute<TResult>(Expression expression)
		{
			ClientExceptionHelper.ThrowIfNull(expression, "expression");
			return this.Execute<TResult>(expression).FirstOrDefault<TResult>();
		}
		object IQueryProvider.Execute(Expression expression)
		{
			ClientExceptionHelper.ThrowIfNull(expression, "expression");
			return this.Execute<object>(expression).FirstOrDefault<object>();
		}
		public virtual IEnumerator<TElement> GetEnumerator<TElement>(Expression expression)
		{
			return this.Execute<TElement>(expression).GetEnumerator();
		}
		private IQueryable CreateQueryInstance(Type elementType, object[] args)
		{
			IQueryable result;
			try
			{
				result = (Activator.CreateInstance(typeof(Query<>).MakeGenericType(new Type[]
				{
					elementType
				}), args) as IQueryable);
			}
			catch (TargetInvocationException ex)
			{
				this.ThrowException(ex.InnerException);
				throw;
			}
			return result;
		}
		private void CheckEntitySubclass(Type entityType)
		{
			if (!entityType.IsSubclassOf(typeof(Entity)))
			{
				this.ThrowException(new ArgumentException(string.Format(CultureInfo.InvariantCulture, "The specified type '{0}' must be a subclass of '{1}'.", new object[]
				{
					entityType,
					typeof(Entity)
				})));
			}
			if (StringExtensions.IsNullOrWhiteSpace(KnownProxyTypesProvider.GetInstance(true).GetNameForType(entityType)))
			{
				this.ThrowException(new ArgumentException(string.Format(CultureInfo.InvariantCulture, "The specified type '{0}' is not a known entity type.", new object[]
				{
					entityType
				})));
			}
		}
		public IEnumerable<TElement> Execute<TElement>(Expression expression)
		{
			QueryProvider.NavigationSource source = null;
			List<QueryProvider.LinkLookup> linkLookups = new List<QueryProvider.LinkLookup>();
			bool throwIfSequenceIsEmpty;
			bool throwIfSequenceNotSingle;
			QueryProvider.Projection projection;
			QueryExpression queryExpression = this.GetQueryExpression(expression, out throwIfSequenceIsEmpty, out throwIfSequenceNotSingle, out projection, ref source, ref linkLookups);
			return this.Execute<TElement>(queryExpression, throwIfSequenceIsEmpty, throwIfSequenceNotSingle, projection, source, linkLookups);
		}
		protected IEnumerable<TElement> Execute<TElement>(QueryExpression qe, bool throwIfSequenceIsEmpty, bool throwIfSequenceNotSingle, QueryProvider.Projection projection, QueryProvider.NavigationSource source, List<QueryProvider.LinkLookup> linkLookups)
		{
			string pagingCookie = null;
			bool moreRecords = false;
			IEnumerable source2 = this.Execute(qe, throwIfSequenceIsEmpty, throwIfSequenceNotSingle, projection, source, linkLookups, out pagingCookie, out moreRecords);
			return new PagedItemCollection<TElement>(source2.Cast<TElement>(), qe, pagingCookie, moreRecords);
		}
		private IEnumerable Execute(QueryExpression qe, bool throwIfSequenceIsEmpty, bool throwIfSequenceNotSingle, QueryProvider.Projection projection, QueryProvider.NavigationSource source, List<QueryProvider.LinkLookup> linkLookups, out string pagingCookie, out bool moreRecords)
		{
			IEnumerable<Entity> enumerable = null;
			pagingCookie = null;
			moreRecords = false;
			OrganizationRequest request;
			if (source != null)
			{
				RelationshipQueryCollection relatedEntitiesQuery = new RelationshipQueryCollection
				{

					{
						source.Relationship,
						qe
					}
				};
				request = new RetrieveRequest
				{
					Target = source.Target,
					ColumnSet = new ColumnSet(),
					RelatedEntitiesQuery = relatedEntitiesQuery
				};
			}
			else
			{
				request = new RetrieveMultipleRequest
				{
					Query = qe
				};
			}
			int? num = null;
			if (qe.PageInfo != null)
			{
				num = new int?(qe.PageInfo.Count);
			}
			bool flag = true;
			bool flag2 = this.AdjustPagingInfo(request, qe, source, out flag);
			EntityCollection entityCollection;
			if (flag2)
			{
				entityCollection = (flag ? this.RetrieveEntityCollection(request, source) : new EntityCollection());
			}
			else
			{
				entityCollection = this.AdjustEntityCollection(request, qe, source);
			}
			if (throwIfSequenceIsEmpty && (entityCollection == null || entityCollection.Entities.Count == 0))
			{
				this.ThrowException(new InvalidOperationException("Sequence contains no elements"));
			}
			if (throwIfSequenceNotSingle && entityCollection != null && entityCollection.Entities.Count > 1)
			{
				this.ThrowException(new InvalidOperationException("Sequence contains more than one element"));
			}
			if (entityCollection != null)
			{
				pagingCookie = entityCollection.PagingCookie;
				moreRecords = entityCollection.MoreRecords;
				int num2 = entityCollection.Entities.Count;
				EntityCollection entityCollection2 = entityCollection;
				while (moreRecords)
				{
					if (num.HasValue && num > num2)
					{
						qe.PageInfo.Count = num.Value - num2;
					}
					else if (num.HasValue && num > 0)
					{
						break;
					}
					if (string.IsNullOrEmpty(pagingCookie))
					{
						this.ThrowException(new NotSupportedException(string.Format(CultureInfo.InvariantCulture, "Paging cookie required to retrieve more records. Update your query to retrieve with total records below {0}", new object[]
						{
							this.RetrievalUpperLimitWithoutPagingCookie
						})));
					}
					qe.PageInfo.PagingCookie = entityCollection2.PagingCookie;
					qe.PageInfo.PageNumber++;
					qe.PageInfo.Count = ((qe.PageInfo.Count < this.RetrievalUpperLimitWithoutPagingCookie) ? qe.PageInfo.Count : this.RetrievalUpperLimitWithoutPagingCookie);
					entityCollection2 = this.RetrieveEntityCollection(request, source);
					if (entityCollection2 == null || entityCollection2.Entities.Count <= 0)
					{
						break;
					}
					pagingCookie = entityCollection2.PagingCookie;
					moreRecords = entityCollection2.MoreRecords;
					num2 += entityCollection2.Entities.Count;
					entityCollection.Entities.AddRange(entityCollection2.Entities);
				}
				enumerable = entityCollection.Entities;
			}
			if (projection != null)
			{
				//return this.ExecuteAnonymousType(enumerable, projection, linkLookups);
			}
			return enumerable.Select(new Func<Entity, Entity>(this.AttachToContext));
		}
		private EntityCollection RetrieveEntityCollection(OrganizationRequest request, QueryProvider.NavigationSource source)
		{
			if (request == null || string.IsNullOrEmpty(request.RequestName) || (!(request.RequestName == "Retrieve") && !(request.RequestName == "RetrieveMultiple")))
			{
				this.ThrowException(new ArgumentException("Invalid request", "request"));
			}
			EntityCollection result;
			if (source != null)
			{
				RetrieveResponse retrieveResponse = this._context.Execute(request) as RetrieveResponse;
				result = (retrieveResponse.Entity.RelatedEntities.Contains(source.Relationship) ? retrieveResponse.Entity.RelatedEntities[source.Relationship] : null);
			}
			else
			{
				RetrieveMultipleResponse retrieveMultipleResponse = this._context.Execute(request) as RetrieveMultipleResponse;
				result = retrieveMultipleResponse.EntityCollection;
			}
			return result;
		}
		private static string ResetPagingNumber(string pagingCookie, int newPage)
		{
			if (!string.IsNullOrEmpty(pagingCookie))
			{
				int num = 0;
				return PagingCookieHelper.ToPagingCookie(PagingCookieHelper.ToContinuationToken(pagingCookie, newPage), out num);
			}
			return pagingCookie;
		}
		private static void ResetPagingInfo(PagingInfo pagingInfo, string pagingCookie, int skipValue)
		{
			if (string.IsNullOrEmpty(pagingCookie))
			{
				pagingInfo.PageNumber = skipValue;
				pagingInfo.Count = 1;
				return;
			}
			pagingInfo.PagingCookie = QueryProvider.ResetPagingNumber(pagingCookie, 1);
			pagingInfo.PageNumber = skipValue + 1;
			pagingInfo.Count = 1;
		}
		private static bool IsPagingCookieNull(EntityCollection entityCollection)
		{
			return entityCollection != null && string.IsNullOrEmpty(entityCollection.PagingCookie);
		}
		private bool AdjustPagingInfo(OrganizationRequest request, QueryExpression qe, QueryProvider.NavigationSource source, out bool moreRecordAfterAdjust)
		{
			moreRecordAfterAdjust = true;
			if (request == null || qe == null || qe.PageInfo == null || !string.IsNullOrEmpty(qe.PageInfo.PagingCookie))
			{
				return true;
			}
			PagingInfo pageInfo = qe.PageInfo;
			EntityCollection entityCollection = null;
			int pageNumber = pageInfo.PageNumber;
			int num = pageInfo.Count;
			num = ((num > this.RetrievalUpperLimitWithoutPagingCookie) ? this.RetrievalUpperLimitWithoutPagingCookie : num);
			if (pageNumber > 0)
			{
				int num2 = pageNumber / this.RetrievalUpperLimitWithoutPagingCookie;
				int num3 = pageNumber % this.RetrievalUpperLimitWithoutPagingCookie;
				if (num2 > 0)
				{
					for (int i = 0; i < num2; i++)
					{
						QueryProvider.ResetPagingInfo(pageInfo, (entityCollection == null) ? null : entityCollection.PagingCookie, this.RetrievalUpperLimitWithoutPagingCookie);
						entityCollection = this.RetrieveEntityCollection(request, source);
						if (QueryProvider.IsPagingCookieNull(entityCollection))
						{
							pageInfo.PageNumber = pageNumber;
							pageInfo.Count = num;
							return false;
						}
						if (entityCollection != null && !entityCollection.MoreRecords)
						{
							moreRecordAfterAdjust = false;
							return true;
						}
					}
				}
				if (num3 > 0 && !QueryProvider.IsPagingCookieNull(entityCollection))
				{
					QueryProvider.ResetPagingInfo(pageInfo, (entityCollection == null) ? null : entityCollection.PagingCookie, num3);
					entityCollection = this.RetrieveEntityCollection(request, source);
					if (QueryProvider.IsPagingCookieNull(entityCollection))
					{
						pageInfo.PageNumber = pageNumber;
						pageInfo.Count = num;
						return false;
					}
					if (entityCollection != null && !entityCollection.MoreRecords)
					{
						moreRecordAfterAdjust = false;
						return true;
					}
				}
				pageInfo.PagingCookie = QueryProvider.ResetPagingNumber(entityCollection.PagingCookie, 1);
				pageInfo.PageNumber = 2;
				pageInfo.Count = num;
			}
			if (pageInfo.PageNumber == 0)
			{
				pageInfo.PageNumber = 1;
			}
			return true;
		}
		private EntityCollection AdjustEntityCollection(OrganizationRequest request, QueryExpression qe, QueryProvider.NavigationSource source)
		{
			if (request == null || qe == null || qe.PageInfo == null || !string.IsNullOrEmpty(qe.PageInfo.PagingCookie))
			{
				return new EntityCollection();
			}
			PagingInfo pageInfo = qe.PageInfo;
			int pageNumber = pageInfo.PageNumber;
			int count = pageInfo.Count;
			if (pageNumber >= this.RetrievalUpperLimitWithoutPagingCookie)
			{
				this.ThrowException(new NotSupportedException(string.Format(CultureInfo.InvariantCulture, "Skipping records beyond {0} is not supported", new object[]
				{
					this.RetrievalUpperLimitWithoutPagingCookie
				})));
			}
			pageInfo.PageNumber = 1;
			if (count > 0)
			{
				pageInfo.Count = ((pageNumber + count > this.RetrievalUpperLimitWithoutPagingCookie) ? this.RetrievalUpperLimitWithoutPagingCookie : (pageNumber + count));
			}
			EntityCollection entityCollection = this.RetrieveEntityCollection(request, source);
			if (entityCollection != null && !string.IsNullOrEmpty(entityCollection.PagingCookie))
			{
				this.ThrowException(new InvalidOperationException("Queries with valid paging cookie should not be executed in this strategy"));
			}
			if (pageNumber > 0)
			{
				EntityCollection entityCollection2 = (pageNumber >= entityCollection.Entities.Count) ? new EntityCollection() : new EntityCollection(entityCollection.Entities.Skip(pageNumber).ToList<Entity>());
				entityCollection2.EntityName = entityCollection.EntityName;
				entityCollection2.MoreRecords = entityCollection.MoreRecords;
				return entityCollection2;
			}
			return entityCollection;
		}
		//private IEnumerable ExecuteAnonymousType(IEnumerable<Entity> entities, QueryProvider.Projection projection, List<QueryProvider.LinkLookup> linkLookups)
		//{
		//	Delegate project = this.CompileExpression(projection.Expression);
		//	return (
		//		from entity in entities
		//		let args = this.BuildProjection(projection, entity, linkLookups)
		//		let element = this.DynamicInvoke(project, args)
		//		select new
		//		{
		//			h__TransparentIdentifier4 = h__TransparentIdentifier4,
		//			result = element as Entity
		//		}).Select(delegate(h__TransparentIdentifier5)
		//	{
		//		if (h__TransparentIdentifier5.result == null || !(h__TransparentIdentifier5.result.Id != Guid.Empty))
		//		{
		//			return h__TransparentIdentifier5.h__TransparentIdentifier4.element;
		//		}
		//		return this.AttachToContext(h__TransparentIdentifier5.result);
		//	});
		//}
		[SecuritySafeCritical]
		private Delegate CompileExpression(LambdaExpression expression)
		{
			Delegate result;
			try
			{
				new ReflectionPermission(ReflectionPermissionFlag.RestrictedMemberAccess).Assert();
				result = expression.Compile();
			}
			finally
			{
				CodeAccessPermission.RevertAssert();
			}
			return result;
		}
		[SecuritySafeCritical]
		private object DynamicInvoke(Delegate project, params object[] args)
		{
			object result;
			try
			{
				new ReflectionPermission(ReflectionPermissionFlag.RestrictedMemberAccess).Assert();
				result = project.DynamicInvoke(args);
			}
			finally
			{
				CodeAccessPermission.RevertAssert();
			}
			return result;
		}
		[SecuritySafeCritical]
		private object ConstructorInvoke(ConstructorInfo ci, object[] parameters)
		{
			object result;
			try
			{
				new ReflectionPermission(ReflectionPermissionFlag.MemberAccess).Assert();
				result = ci.Invoke(parameters);
			}
			finally
			{
				CodeAccessPermission.RevertAssert();
			}
			return result;
		}
		private Entity AttachToContext(Entity entity)
		{
			return this._context.MergeEntity(entity);
		}
		private object[] BuildProjection(QueryProvider.Projection projection, Entity entity, IList<QueryProvider.LinkLookup> linkLookups)
		{
			if (entity == null)
			{
				return null;
			}
			if (linkLookups.Count == 0)
			{
				return new Entity[]
				{
					this.AttachToContext(entity)
				};
			}
			ReadOnlyCollection<ParameterExpression> parameters = projection.Expression.Parameters;
			if (linkLookups.Count == 2 && parameters.Count == 2)
			{
				object obj = (linkLookups[1].Link.JoinOperator == JoinOperator.LeftOuter) ? this.BuildProjection(null, projection.MethodName, parameters[0].Type, entity, linkLookups) : entity;
				return new object[]
				{
					obj,
					this.BuildProjectionParameter(parameters[1].Type, entity, linkLookups[1])
				};
			}
			return (
				from parameter in parameters
				select this.BuildProjection(null, projection.MethodName, parameter.Type, entity, linkLookups)).ToArray<object>();
		}
		private object BuildProjection(string environment, string projectingMethodName, Type entityType, Entity entity, IEnumerable<QueryProvider.LinkLookup> linkLookups)
		{
			if (this.IsEntity(entityType))
			{
				object obj = this.BuildProjectionParameter(null, projectingMethodName, entityType, entity, linkLookups);
				return obj ?? entity;
			}
			ConstructorInfo[] constructors = entityType.GetConstructors();
			if (QueryProvider.IsAnonymousType(entityType) && constructors.Length != 1)
			{
				this.ThrowException(new InvalidOperationException("The result selector of the 'Join' operation is not returning a valid anonymous type."));
			}
			ConstructorInfo constructorInfo = constructors.First<ConstructorInfo>();
			ParameterInfo[] parameters = constructorInfo.GetParameters();
			if (parameters.Length != 2)
			{
				this.ThrowException(new InvalidOperationException("The result selector of the 'Join' operation must return an anonymous type of two properties."));
			}
			ParameterInfo parameterInfo = parameters[0];
			ParameterInfo parameterInfo2 = parameters[1];
			if (this.IsEntity(parameterInfo.ParameterType) && this.IsEntity(parameterInfo2.ParameterType))
			{
				object obj2 = this.BuildProjectionParameter(parameterInfo, environment, projectingMethodName, parameterInfo.ParameterType, entity, linkLookups);
				object obj3 = this.BuildProjectionParameter(parameterInfo2, environment, projectingMethodName, parameterInfo2.ParameterType, entity, linkLookups);
				return this.ConstructorInvoke(constructorInfo, new object[]
				{
					obj2,
					obj3
				});
			}
			if (this.IsEntity(parameterInfo2.ParameterType))
			{
				object obj4 = this.BuildProjectionParameter(parameterInfo, environment, projectingMethodName, entity, linkLookups);
				object obj5 = this.BuildProjectionParameter(parameterInfo2, environment, projectingMethodName, parameterInfo2.ParameterType, entity, linkLookups);
				return this.ConstructorInvoke(constructorInfo, new object[]
				{
					obj4,
					obj5
				});
			}
			if (this.IsEntity(parameterInfo.ParameterType))
			{
				object obj6 = this.BuildProjectionParameter(parameterInfo, environment, projectingMethodName, parameterInfo.ParameterType, entity, linkLookups);
				object obj7 = this.BuildProjectionParameter(parameterInfo2, environment, projectingMethodName, entity, linkLookups);
				return this.ConstructorInvoke(constructorInfo, new object[]
				{
					obj6,
					obj7
				});
			}
			this.ThrowException(new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Invalid left '{0}' and right '{1}' parameters.", new object[]
			{
				parameterInfo.ParameterType.Name,
				parameterInfo2.ParameterType.Name
			})));
			return null;
		}
		private object BuildProjectionParameter(ParameterInfo parameter, string environment, string projectingMethodName, Entity entity, IEnumerable<QueryProvider.LinkLookup> linkLookups)
		{
			if (parameter.ParameterType.IsGenericType && parameter.ParameterType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
			{
				return null;
			}
			string environment2 = QueryProvider.GetEnvironment(parameter, environment);
			return this.BuildProjection(environment2, projectingMethodName, parameter.ParameterType, entity, linkLookups);
		}
		private object BuildProjectionParameter(ParameterInfo pi, string environment, string projectingMethodName, Type entityType, Entity entity, IEnumerable<QueryProvider.LinkLookup> linkLookups)
		{
			return this.BuildProjectionParameter(QueryProvider.GetEnvironment(pi, environment), projectingMethodName, entityType, entity, linkLookups);
		}
		private object BuildProjectionParameter(string environment, string projectingMethodName, Type entityType, Entity entity, IEnumerable<QueryProvider.LinkLookup> linkLookups)
		{
			QueryProvider.LinkLookup linkLookup = (projectingMethodName == "SelectMany") ? linkLookups.SingleOrDefault((QueryProvider.LinkLookup l) => l.SelectManyEnvironment != null && l.SelectManyEnvironment == environment) : linkLookups.SingleOrDefault((QueryProvider.LinkLookup l) => l.Environment == environment);
			if (linkLookup != null)
			{
				return this.BuildProjectionParameter(entityType, entity, linkLookup);
			}
			this.ThrowException(new InvalidOperationException("The projection property does not match an existing entity binding."));
			return null;
		}
		private object BuildProjectionParameter(Type entityType, Entity entity, QueryProvider.LinkLookup link)
		{
			if (link.Link == null)
			{
				return entity;
			}
			Entity entity2 = (entityType == typeof(Entity)) ? new Entity(link.Link.LinkToEntityName) : (Activator.CreateInstance(entityType) as Entity);
			string entityAlias = string.Format(CultureInfo.InvariantCulture, "{0}.", new object[]
			{
				link.Link.EntityAlias
			});
			int aliasIndex = entityAlias.Length;
			var enumerable = 
				from a in entity.Attributes
				where a.Value is AliasedValue && a.Key.StartsWith(entityAlias, StringComparison.Ordinal)
				select new
				{
					Key = a.Key.Substring(aliasIndex),
					Value = (a.Value as AliasedValue).Value
				};
			foreach (var current in enumerable)
			{
				entity2.Attributes.Add(current.Key, current.Value);
			}
			return entity2;
		}
		private static string GetEnvironment(ParameterInfo pi, string environment)
		{
			if (environment == null)
			{
				return pi.Name;
			}
			return string.Format(CultureInfo.InvariantCulture, "{0}.{1}", new object[]
			{
				environment,
				pi.Name
			});
		}
		public QueryExpression Translate(Expression expression)
		{
			QueryProvider.NavigationSource navigationSource = null;
			List<QueryProvider.LinkLookup> list = null;
			bool flag;
			bool flag2;
			QueryProvider.Projection projection;
			return this.GetQueryExpression(expression, out flag, out flag2, out projection, ref navigationSource, ref list);
		}
		protected virtual bool IsValidFollowingMethod(string method, string next)
		{
			IEnumerable<string> source;
			return QueryProvider._followingMethodLookup.TryGetValue(method, out source) && source.Contains(next);
		}
		private bool IsValidMethod(string method)
		{
			return QueryProvider._followingMethodLookup.ContainsKey(method);
		}
		private QueryExpression GetQueryExpression(Expression expression, out bool throwIfSequenceIsEmpty, out bool throwIfSequenceNotSingle, out QueryProvider.Projection projection, ref QueryProvider.NavigationSource source, ref List<QueryProvider.LinkLookup> linkLookups)
		{
			throwIfSequenceIsEmpty = false;
			throwIfSequenceNotSingle = false;
			projection = null;
			int? num = null;
			int? num2 = null;
			QueryExpression queryExpression = new QueryExpression();
			List<MethodCallExpression> list = expression.GetMethodsPostorder().ToList<MethodCallExpression>();
			bool flag = list.Count > 0 && (list[0].Method.Name == "Join" || list[0].Method.Name == "GroupJoin");
			for (int i = 0; i < list.Count; i++)
			{
				MethodCallExpression methodCallExpression = list[i];
				string name = methodCallExpression.Method.Name;
				if (!this.IsValidMethod(name))
				{
					this.ThrowException(new NotSupportedException(string.Format(CultureInfo.InvariantCulture, "The method '{0}' is not supported.", new object[]
					{
						name
					})));
				}
				if (i > 0)
				{
					string name2 = list[i - 1].Method.Name;
					if (!this.IsValidFollowingMethod(name2, name))
					{
						this.ThrowException(new NotSupportedException(string.Format(CultureInfo.InvariantCulture, "The method '{0}' cannot follow the method '{1}' or is not supported. Try writing the query in terms of supported methods or call the 'AsEnumerable' or 'ToList' method before calling unsupported methods.", new object[]
						{
							name,
							name2
						})));
					}
				}
				string key;
				switch (key = name)
				{
				case "Join":
					this.TranslateJoin(queryExpression, list, ref i, out projection, out linkLookups);
					break;
				case "GroupJoin":
					this.TranslateGroupJoin(queryExpression, list, ref i, out projection, out linkLookups);
					break;
				case "FirstOrDefault":
				case "SingleOrDefault":
				case "First":
				case "Single":
				case "Where":
				{
					if (name != "Where")
					{
						num2 = new int?(1);
					}
					if (name == "First" || name == "Single")
					{
						throwIfSequenceIsEmpty = true;
					}
					if (name == "SingleOrDefault" || name == "Single")
					{
						num2 = new int?(2);
						throwIfSequenceNotSingle = true;
					}
					string parameterName;
					Expression methodCallBody = this.GetMethodCallBody(methodCallExpression, out parameterName);
					if (methodCallBody != null)
					{
						this.TranslateWhere(queryExpression, parameterName, methodCallBody, linkLookups);
					}
					break;
				}
				case "OrderBy":
				case "ThenBy":
				{
					string parameterName2;
					Expression methodCallBody2 = this.GetMethodCallBody(methodCallExpression, out parameterName2);
					this.TranslateOrderBy(queryExpression, methodCallBody2, OrderType.Ascending, parameterName2, linkLookups);
					break;
				}
				case "OrderByDescending":
				case "ThenByDescending":
				{
					string parameterName3;
					Expression methodCallBody3 = this.GetMethodCallBody(methodCallExpression, out parameterName3);
					this.TranslateOrderBy(queryExpression, methodCallBody3, OrderType.Descending, parameterName3, linkLookups);
					break;
				}
				case "Select":
				{
					if (linkLookups != null && !flag)
					{
						linkLookups.Clear();
					}
					this.TranslateEntityName(queryExpression, expression, methodCallExpression);
					LambdaExpression lambdaExpression = (methodCallExpression.Arguments[1] as UnaryExpression).Operand as LambdaExpression;
					projection = new QueryProvider.Projection(name, lambdaExpression);
					Expression expression2 = this.TranslateSelect(list, i, queryExpression, lambdaExpression, ref source);
					if (expression2 != null)
					{
						return this.GetQueryExpression(expression2, out throwIfSequenceIsEmpty, out throwIfSequenceNotSingle, out projection, ref source, ref linkLookups);
					}
					break;
				}
				case "Skip":
					num = new int?((int)(methodCallExpression.Arguments[1] as ConstantExpression).Value);
					if (num.HasValue && num < 0)
					{
						this.ThrowException(new NotSupportedException("Skip operator does not support negative values."));
					}
					break;
				case "Take":
					num2 = new int?((int)(methodCallExpression.Arguments[1] as ConstantExpression).Value);
					if (num2.HasValue && num2 <= 0)
					{
						this.ThrowException(new NotSupportedException("Take/Top operators only support positive values."));
					}
					break;
				case "Distinct":
					queryExpression.Distinct = true;
					break;
				case "SelectMany":
				{
					if (linkLookups != null && !flag)
					{
						linkLookups.Clear();
					}
					this.TranslateEntityName(queryExpression, expression, methodCallExpression);
					LambdaExpression exp = (methodCallExpression.Arguments[1] as UnaryExpression).Operand as LambdaExpression;
					Expression expression3 = this.TranslateSelectMany(list, i, queryExpression, exp, ref source);
					return this.GetQueryExpression(expression3, out throwIfSequenceIsEmpty, out throwIfSequenceNotSingle, out projection, ref source, ref linkLookups);
				}
				}
			}
			if (projection != null)
			{
				this.TranslateSelect(queryExpression, projection.Expression, linkLookups);
				this.FixOrderBy(queryExpression, projection.Expression);
			}
			if (!this.BuildPagingInfo(queryExpression, num, num2))
			{
				this.ThrowException(new NotSupportedException("The 'Skip' value must be a multiple of the 'Take/Top' value."));
			}
			this.FixEntityName(queryExpression, expression);
			this.FixColumnSet(queryExpression);
			return queryExpression;
		}
		protected virtual bool BuildPagingInfo(QueryExpression qe, int? skipVal, int? takeVal)
		{
			if (!skipVal.HasValue && !takeVal.HasValue)
			{
				return true;
			}
			if (qe.PageInfo == null)
			{
				qe.PageInfo = new PagingInfo();
			}
			if (skipVal.HasValue && skipVal.Value > 0)
			{
				qe.PageInfo.PageNumber = skipVal.Value;
			}
			if (takeVal.HasValue && takeVal.Value > 0)
			{
				qe.PageInfo.Count = takeVal.Value;
			}
			return true;
		}
		protected virtual void FixOrderBy(QueryExpression qe, LambdaExpression exp)
		{
		}
		protected virtual void FixEntityName(QueryExpression qe, Expression expression)
		{
			this.TranslateEntityName(qe, expression, null);
		}
		protected virtual void FixColumnSet(QueryExpression qe)
		{
			qe.ColumnSet = ((qe.ColumnSet == null || qe.ColumnSet.Columns.Count == 0) ? new ColumnSet(true) : qe.ColumnSet);
		}
		private void TranslateJoin(QueryExpression qe, IList<MethodCallExpression> methods, ref int i, out QueryProvider.Projection projection, out List<QueryProvider.LinkLookup> linkLookups)
		{
			int num = 0;
			List<Tuple<string, string, LinkEntity, string>> list = null;
			do
			{
				MethodCallExpression methodCallExpression = methods[i];
				projection = new QueryProvider.Projection(methodCallExpression.Method.Name, (methodCallExpression.Arguments[4] as UnaryExpression).Operand as LambdaExpression);
				string text;
				string environment;
				if (i < methods.Count - 1)
				{
					environment = this.GetEnvironmentForParameter(projection.Expression, 0);
					text = this.GetEnvironmentForParameter(projection.Expression, 1);
				}
				else
				{
					text = (environment = null);
				}
				string text2 = null;
				UnaryExpression unaryExpression = methodCallExpression.Arguments[2] as UnaryExpression;
				LambdaExpression lambdaExpression = unaryExpression.Operand as LambdaExpression;
				string name = lambdaExpression.Parameters.First<ParameterExpression>().Name;
				Expression body = lambdaExpression.Body;
				Expression exp = this.FindValidEntityExpression(body, "join");
				string linkFromAttributeName = this.TranslateExpressionToAttributeName(exp, false, out text2);
				UnaryExpression unaryExpression2 = methodCallExpression.Arguments[3] as UnaryExpression;
				LambdaExpression lambdaExpression2 = unaryExpression2.Operand as LambdaExpression;
				string name2 = lambdaExpression2.Parameters.First<ParameterExpression>().Name;
				Expression body2 = lambdaExpression2.Body;
				Expression exp2 = this.FindValidEntityExpression(body2, "join");
				string linkToAttributeName = this.TranslateExpressionToAttributeName(exp2, false, out text2);
				string entityLogicalName = ((methodCallExpression.Arguments[1] as ConstantExpression).Value as IEntityQuery).EntityLogicalName;
				LinkEntity linkEntity;
				if (list == null)
				{
					qe.EntityName = ((methodCallExpression.Arguments[0] as ConstantExpression).Value as IEntityQuery).EntityLogicalName;
					list = new List<Tuple<string, string, LinkEntity, string>>
					{
						new Tuple<string, string, LinkEntity, string>(environment, environment, null, name)
					};
					linkEntity = qe.AddLink(entityLogicalName, linkFromAttributeName, linkToAttributeName, JoinOperator.Inner);
				}
				else
				{
					if (environment != null)
					{
						list = (
							from l in list
							select new Tuple<string, string, LinkEntity, string>(l.Item1, environment + "." + l.Item2, l.Item3, l.Item4)).ToList<Tuple<string, string, LinkEntity, string>>();
					}
					string parentMember = this.GetUnderlyingMemberExpression(exp).Member.Name;
					LinkEntity item = list.Single((Tuple<string, string, LinkEntity, string> l) => l.Item1 == parentMember).Item3;
					linkEntity = ((item == null) ? qe.AddLink(entityLogicalName, linkFromAttributeName, linkToAttributeName, JoinOperator.Inner) : item.AddLink(entityLogicalName, linkFromAttributeName, linkToAttributeName, JoinOperator.Inner));
				}
				linkEntity.EntityAlias = string.Format(CultureInfo.InvariantCulture, "{0}_{1}", new object[]
				{
					name2,
					num++
				});
				list.Add(new Tuple<string, string, LinkEntity, string>(text, text, linkEntity, name2));
				i++;
			}
			while (i < methods.Count && methods[i].Method.Name == "Join");
			i--;
			linkLookups = (
				from l in list
				select new QueryProvider.LinkLookup(l.Item4, l.Item2, l.Item3)).ToList<QueryProvider.LinkLookup>();
		}
		private void TranslateGroupJoin(QueryExpression qe, IList<MethodCallExpression> methods, ref int i, out QueryProvider.Projection projection, out List<QueryProvider.LinkLookup> linkLookups)
		{
			MethodCallExpression methodCallExpression = methods[i];
			List<QueryProvider.LinkLookup> list;
			this.TranslateJoin(qe, methods, ref i, out projection, out list);
			i++;
			if (i + 1 > methods.Count || !this.IsValidLeftOuterSelectManyExpression(methods[i]))
			{
				this.ThrowException(new NotSupportedException("The 'GroupJoin' operation must be followed by a 'SelectMany' operation where the collection selector is invoking the 'DefaultIfEmpty' method."));
			}
			MethodCallExpression methodCallExpression2 = methods[i];
			LambdaExpression expression;
			if (methodCallExpression2.Arguments.Count == 3)
			{
				expression = ((methodCallExpression2.Arguments[2] as UnaryExpression).Operand as LambdaExpression);
			}
			else
			{
				ParameterExpression parameterExpression = ((methodCallExpression2.Arguments[1] as UnaryExpression).Operand as LambdaExpression).Parameters[0];
				ParameterExpression parameterExpression2 = ((methodCallExpression.Arguments[3] as UnaryExpression).Operand as LambdaExpression).Parameters[0];
				expression = Expression.Lambda(parameterExpression2, new ParameterExpression[]
				{
					parameterExpression,
					parameterExpression2
				});
			}
			projection = new QueryProvider.Projection(methodCallExpression2.Method.Name, expression);
			string environmentForParameter = this.GetEnvironmentForParameter(projection.Expression, 0);
			string environmentForParameter2 = this.GetEnvironmentForParameter(projection.Expression, 1);
			linkLookups = new List<QueryProvider.LinkLookup>
			{
				new QueryProvider.LinkLookup(list[0].ParameterName, (environmentForParameter != null) ? string.Format(CultureInfo.InvariantCulture, "{0}.{1}", new object[]
				{
					environmentForParameter,
					list[0].Environment
				}) : list[0].Environment, list[0].Link, list[0].Environment),
				new QueryProvider.LinkLookup(list[1].ParameterName, environmentForParameter2, list[1].Link)
			};
			list[1].Link.JoinOperator = JoinOperator.LeftOuter;
		}
		private bool IsValidLeftOuterSelectManyExpression(MethodCallExpression mce)
		{
			if (mce.Method.Name != "SelectMany")
			{
				return false;
			}
			UnaryExpression unaryExpression = mce.Arguments[1] as UnaryExpression;
			if (unaryExpression == null)
			{
				return false;
			}
			LambdaExpression lambdaExpression = unaryExpression.Operand as LambdaExpression;
			if (lambdaExpression == null)
			{
				return false;
			}
			MethodCallExpression methodCallExpression = lambdaExpression.Body as MethodCallExpression;
			if (methodCallExpression == null)
			{
				return false;
			}
			if (methodCallExpression.Method.Name != "DefaultIfEmpty")
			{
				return false;
			}
			if (methodCallExpression.Arguments.Count != 1)
			{
				return false;
			}
			if (mce.Arguments.Count == 2)
			{
				return true;
			}
			if (mce.Arguments.Count != 3)
			{
				return false;
			}
			UnaryExpression unaryExpression2 = mce.Arguments[2] as UnaryExpression;
			if (unaryExpression2 == null)
			{
				return false;
			}
			LambdaExpression lambdaExpression2 = unaryExpression2.Operand as LambdaExpression;
			return lambdaExpression2 != null && lambdaExpression2.Parameters.Count == 2;
		}
		private string GetEnvironmentForParameter(LambdaExpression projection, int index)
		{
			NewExpression newExpression = projection.Body as NewExpression;
			if (newExpression == null)
			{
				return null;
			}
			ParameterExpression parameter = projection.Parameters[index];
			ReadOnlyCollection<Expression> arguments = newExpression.Arguments;
			Expression expression = arguments.FirstOrDefault((Expression arg) => arg == parameter);
			if (expression == null)
			{
				return null;
			}
			int index2 = arguments.IndexOf(expression);
			return newExpression.Members[index2].Name;
		}
		private ConditionOperator NegateOperator(ConditionOperator op)
		{
			return QueryProvider._operatorNegationLookup[op];
		}
		private LogicalOperator NegateOperator(LogicalOperator op)
		{
			return QueryProvider._logicalOperatorNegationLookup[op];
		}
		private void TranslateWhere(QueryExpression qe, string parameterName, Expression exp, List<QueryProvider.LinkLookup> linkLookups)
		{
			this.TranslateWhereBoolean(parameterName, exp, null, this.GetFilter(parameterName, qe, linkLookups), linkLookups, null, false);
		}
		private void TranslateWhere(string parameterName, BinaryExpression be, QueryProvider.FilterExpressionWrapper parentFilter, Func<Expression, QueryProvider.FilterExpressionWrapper> getFilter, List<QueryProvider.LinkLookup> linkLookups, bool negate)
		{
			if (QueryProvider._booleanLookup.ContainsKey(be.NodeType))
			{
				Expression entityExpression = this.FindEntityExpression(be.Left);
				parentFilter = this.GetFilter(entityExpression, parentFilter, getFilter);
				QueryProvider.FilterExpressionWrapper filterExpressionWrapper = new QueryProvider.FilterExpressionWrapper(parentFilter.Filter.AddFilter(QueryProvider._booleanLookup[be.NodeType]), parentFilter.Alias);
				filterExpressionWrapper.Filter.FilterOperator = (negate ? this.NegateOperator(filterExpressionWrapper.Filter.FilterOperator) : filterExpressionWrapper.Filter.FilterOperator);
				this.TranslateWhereBoolean(parameterName, be.Left, filterExpressionWrapper, getFilter, linkLookups, be, negate);
				this.TranslateWhereBoolean(parameterName, be.Right, filterExpressionWrapper, getFilter, linkLookups, be, negate);
				return;
			}
			if (QueryProvider._conditionLookup.ContainsKey(be.NodeType))
			{
				bool negate2 = negate;
				MethodCallExpression methodCallExpression = this.TranslateWhere(be.Left, ref negate2) as MethodCallExpression;
				if (methodCallExpression != null && (methodCallExpression.Method.Name == "Compare" || QueryProvider._supportedMethods.Contains(methodCallExpression.Method.Name)))
				{
					this.TranslateWhereBoolean(parameterName, methodCallExpression, parentFilter, getFilter, linkLookups, be, negate2);
					return;
				}
				this.TranslateWhereCondition(be, parentFilter, getFilter, this.GetLinkLookup(parameterName, linkLookups), negate);
			}
		}
		protected virtual Expression TranslateWhere(Expression exp, ref bool negate)
		{
			UnaryExpression unaryExpression = exp as UnaryExpression;
			if (unaryExpression == null || unaryExpression.NodeType != ExpressionType.Not)
			{
				return exp;
			}
			negate = !negate;
			return this.TranslateWhere(unaryExpression.Operand, ref negate);
		}
		protected virtual void TranslateWhereBoolean(string parameterName, Expression exp, QueryProvider.FilterExpressionWrapper parentFilter, Func<Expression, QueryProvider.FilterExpressionWrapper> getFilter, List<QueryProvider.LinkLookup> linkLookups, BinaryExpression parent, bool negate)
		{
			BinaryExpression binaryExpression = exp as BinaryExpression;
			UnaryExpression unaryExpression = exp as UnaryExpression;
			MethodCallExpression methodCallExpression = exp as MethodCallExpression;
			if (binaryExpression != null)
			{
				ConstantExpression constantExpression = binaryExpression.Left as ConstantExpression;
				if (constantExpression != null && ((binaryExpression.NodeType == ExpressionType.AndAlso && object.Equals(constantExpression.Value, true)) || (binaryExpression.NodeType == ExpressionType.OrElse && object.Equals(constantExpression.Value, false))))
				{
					this.TranslateWhereBoolean(parameterName, binaryExpression.Right, parentFilter, getFilter, linkLookups, parent, negate);
					return;
				}
				this.TranslateWhere(parameterName, binaryExpression, parentFilter, getFilter, linkLookups, negate);
				return;
			}
			else
			{
				if (methodCallExpression != null)
				{
					this.TranslateWhereMethodCall(methodCallExpression, parentFilter, getFilter, this.GetLinkLookup(parameterName, linkLookups), parent, negate);
					return;
				}
				if (unaryExpression != null)
				{
					if (unaryExpression.NodeType == ExpressionType.Convert)
					{
						this.TranslateWhereBoolean(parameterName, unaryExpression.Operand, parentFilter, getFilter, linkLookups, parent, negate);
						return;
					}
					if (unaryExpression.NodeType == ExpressionType.Not)
					{
						this.TranslateWhereBoolean(parameterName, unaryExpression.Operand, parentFilter, getFilter, linkLookups, parent, !negate);
						return;
					}
				}
				else if (exp.Type == typeof(bool))
				{
					this.TranslateWhere(parameterName, Expression.Equal(exp, Expression.Constant(true)), parentFilter, getFilter, linkLookups, negate);
				}
				return;
			}
		}
		private string GetLinkEntityAlias(Expression expression, Func<Expression, QueryProvider.LinkLookup> getLinkLookup)
		{
			string result = null;
			QueryProvider.LinkLookup linkLookup = getLinkLookup(expression);
			if (linkLookup != null && linkLookup.Link != null)
			{
				result = linkLookup.Link.EntityAlias;
			}
			return result;
		}
		private void TranslateWhereCondition(BinaryExpression be, QueryProvider.FilterExpressionWrapper parentFilter, Func<Expression, QueryProvider.FilterExpressionWrapper> getFilter, Func<Expression, QueryProvider.LinkLookup> getLinkLookup, bool negate)
		{
			Expression expression = this.FindValidEntityExpression(be.Left, "where");
			string alias = null;
			string attributeName = this.TranslateExpressionToAttributeName(expression, false, out alias);
			object obj = this.TranslateExpressionToConditionValue(be.Right, new ParameterExpression[0]);
			string linkEntityAlias = this.GetLinkEntityAlias(expression, getLinkLookup);
			ConditionExpression conditionExpression = null;
			if (obj != null)
			{
				conditionExpression = new ConditionExpression(linkEntityAlias, attributeName, QueryProvider._conditionLookup[be.NodeType], obj);
			}
			else if (be.NodeType == ExpressionType.Equal)
			{
				conditionExpression = new ConditionExpression(linkEntityAlias, attributeName, ConditionOperator.Null);
			}
			else if (be.NodeType == ExpressionType.NotEqual)
			{
				conditionExpression = new ConditionExpression(linkEntityAlias, attributeName, ConditionOperator.NotNull);
			}
			else
			{
				this.ThrowException(new NotSupportedException("Invalid 'where' condition."));
			}
			conditionExpression.Operator = (negate ? this.NegateOperator(conditionExpression.Operator) : conditionExpression.Operator);
			this.AddCondition(this.GetFilter(expression, parentFilter, getFilter), conditionExpression, alias);
		}
		private void TranslateWhereMethodCall(MethodCallExpression mce, QueryProvider.FilterExpressionWrapper parentFilter, Func<Expression, QueryProvider.FilterExpressionWrapper> getFilter, Func<Expression, QueryProvider.LinkLookup> getLinkLookup, BinaryExpression parent, bool negate)
		{
			string alias = null;
			if (QueryProvider._supportedMethods.Contains(mce.Method.Name) && mce.Arguments.Count == 1)
			{
				Expression expression = this.FindValidEntityExpression(mce.Object, "where");
				string linkEntityAlias = this.GetLinkEntityAlias(expression, getLinkLookup);
				string attributeName = this.TranslateExpressionToAttributeName(expression, false, out alias);
				object value = this.TranslateExpressionToConditionValue(mce.Arguments[0], new ParameterExpression[0]);
				if (parent != null)
				{
					if (parent.NodeType == ExpressionType.NotEqual)
					{
						negate = !negate;
					}
					if (parent.NodeType == ExpressionType.Equal || parent.NodeType == ExpressionType.NotEqual)
					{
						object objA = this.TranslateExpressionToConditionValue(parent.Right, new ParameterExpression[0]);
						if (object.Equals(objA, false))
						{
							negate = !negate;
						}
					}
				}
				ConditionExpression conditionExpression = this.TranslateConditionMethodExpression(mce, attributeName, value);
				conditionExpression.EntityName = linkEntityAlias;
				conditionExpression.Operator = (negate ? this.NegateOperator(conditionExpression.Operator) : conditionExpression.Operator);
				this.AddCondition(this.GetFilter(expression, parentFilter, getFilter), conditionExpression, alias);
				return;
			}
			if (mce.Method.Name == "Compare" && mce.Arguments.Count == 2)
			{
				Expression expression2 = this.FindValidEntityExpression(mce.Arguments[0], "where");
				string linkEntityAlias2 = this.GetLinkEntityAlias(expression2, getLinkLookup);
				string attributeName2 = this.TranslateExpressionToAttributeName(expression2, false, out alias);
				object value2 = this.TranslateExpressionToConditionValue(mce.Arguments[1], new ParameterExpression[0]);
				if (parent != null)
				{
					object objA2 = this.TranslateExpressionToConditionValue(parent.Right, new ParameterExpression[0]);
					ConditionOperator conditionOperator;
					if (object.Equals(objA2, 0) && QueryProvider._conditionLookup.TryGetValue(parent.NodeType, out conditionOperator))
					{
						ConditionExpression conditionExpression2 = new ConditionExpression(linkEntityAlias2, attributeName2, conditionOperator, value2);
						conditionExpression2.Operator = (negate ? this.NegateOperator(conditionExpression2.Operator) : conditionExpression2.Operator);
						this.AddCondition(this.GetFilter(expression2, parentFilter, getFilter), conditionExpression2, alias);
						return;
					}
				}
			}
			else
			{
				if (mce.Method.Name == "Like" && mce.Arguments.Count == 2)
				{
					Expression expression3 = this.FindValidEntityExpression(mce.Arguments[0], "where");
					string linkEntityAlias3 = this.GetLinkEntityAlias(expression3, getLinkLookup);
					string attributeName3 = this.TranslateExpressionToAttributeName(expression3, false, out alias);
					object value3 = this.TranslateExpressionToConditionValue(mce.Arguments[1], new ParameterExpression[0]);
					ConditionExpression conditionExpression3 = new ConditionExpression(linkEntityAlias3, attributeName3, ConditionOperator.Like, value3);
					conditionExpression3.Operator = (negate ? this.NegateOperator(conditionExpression3.Operator) : conditionExpression3.Operator);
					this.AddCondition(this.GetFilter(expression3, parentFilter, getFilter), conditionExpression3, alias);
					return;
				}
				if ((parent == null || QueryProvider._booleanLookup.ContainsKey(parent.NodeType)) && mce.Type.GetUnderlyingType() == typeof(bool))
				{
					Expression expression4 = this.FindValidEntityExpression(mce, "where");
					string linkEntityAlias4 = this.GetLinkEntityAlias(expression4, getLinkLookup);
					string attributeName4 = this.TranslateExpressionToAttributeName(expression4, false, out alias);
					ConditionExpression conditionExpression4 = new ConditionExpression(linkEntityAlias4, attributeName4, ConditionOperator.Equal, true);
					conditionExpression4.Operator = (negate ? this.NegateOperator(conditionExpression4.Operator) : conditionExpression4.Operator);
					this.AddCondition(this.GetFilter(expression4, parentFilter, getFilter), conditionExpression4, alias);
				}
			}
		}
		private ConditionExpression TranslateConditionMethodExpression(MethodCallExpression mce, string attributeName, object value)
		{
			ConditionExpression result = null;
			string name;
			if ((name = mce.Method.Name) != null)
			{
				if (name == "Equals")
				{
					result = ((value == null) ? new ConditionExpression(attributeName, ConditionOperator.Null) : new ConditionExpression(attributeName, ConditionOperator.Equal, value));
					return result;
				}
				if (name == "Contains")
				{
					result = new ConditionExpression(attributeName, ConditionOperator.Like, "%" + value + "%");
					return result;
				}
				if (name == "StartsWith")
				{
					result = new ConditionExpression(attributeName, ConditionOperator.Like, value + "%");
					return result;
				}
				if (name == "EndsWith")
				{
					result = new ConditionExpression(attributeName, ConditionOperator.Like, "%" + value);
					return result;
				}
			}
			this.ThrowException(new NotSupportedException(string.Format(CultureInfo.InvariantCulture, "The method '{0}' is not supported.", new object[]
			{
				mce.Method.Name
			})));
			return result;
		}
		private void AddCondition(QueryProvider.FilterExpressionWrapper filter, ConditionExpression condition, string alias)
		{
			if (filter.Alias != alias)
			{
				this.ThrowException(new NotSupportedException("filter conditions of different entity types, in the same expression, are not supported"));
			}
			filter.Filter.AddCondition(condition);
		}
		private QueryProvider.FilterExpressionWrapper GetFilter(Expression entityExpression, QueryProvider.FilterExpressionWrapper parentFilter, Func<Expression, QueryProvider.FilterExpressionWrapper> getFilter)
		{
			if (parentFilter != null)
			{
				return parentFilter;
			}
			return getFilter(entityExpression);
		}
		protected virtual Func<Expression, QueryProvider.LinkLookup> GetLinkLookup(string parameterName, List<QueryProvider.LinkLookup> linkLookups)
		{
			return delegate(Expression exp)
			{
				string expName = this.GetUnderlyingParameterExpressionName(exp);
				return linkLookups.SingleOrDefault(delegate(QueryProvider.LinkLookup link)
				{
					string text = string.Format(CultureInfo.InvariantCulture, "{0}.{1}", new object[]
					{
						parameterName,
						link.Environment
					});
					return expName == text || (expName.StartsWith(text) && expName[text.Length] == '.');
				});
			};
		}
		protected virtual Func<Expression, QueryProvider.FilterExpressionWrapper> GetFilter(string parameterName, QueryExpression qe, List<QueryProvider.LinkLookup> linkLookups)
		{
			return (Expression exp) => new QueryProvider.FilterExpressionWrapper(qe.Criteria, null);
		}
		protected virtual void TranslateOrderBy(QueryExpression qe, Expression exp, OrderType orderType, string parameterName, List<QueryProvider.LinkLookup> linkLookups)
		{
			if (this.IsEntityExpression(exp))
			{
				this.ValidateRootEntity("orderBy", exp, parameterName, linkLookups);
				string text = null;
				string attributeName = this.TranslateExpressionToAttributeName(exp, false, out text);
				qe.AddOrder(attributeName, orderType);
				return;
			}
			this.TranslateNonEntityExpressionOrderBy(qe, exp, orderType);
		}
		protected virtual void TranslateNonEntityExpressionOrderBy(QueryExpression qe, Expression exp, OrderType orderType)
		{
			this.ThrowException(new NotSupportedException("The 'orderBy' call must specify property names."));
		}
		private void ValidateRootEntity(string operationName, Expression exp, string parameterName, List<QueryProvider.LinkLookup> linkLookups)
		{
			if (linkLookups != null)
			{
				string underlyingParameterExpressionName = this.GetUnderlyingParameterExpressionName(exp);
				QueryProvider.LinkLookup linkLookup = linkLookups.SingleOrDefault((QueryProvider.LinkLookup l) => l.Link == null);
				if (linkLookup != null && string.Format(CultureInfo.InvariantCulture, "{0}.{1}", new object[]
				{
					parameterName,
					linkLookup.Environment
				}) != underlyingParameterExpressionName)
				{
					this.ThrowException(new NotSupportedException(string.Format(CultureInfo.InvariantCulture, "The '{0}' expression is limited to invoking the '{1}' parameter.", new object[]
					{
						operationName,
						linkLookup.ParameterName
					})));
				}
			}
		}
		private Expression TranslateSelect(IList<MethodCallExpression> methods, int i, QueryExpression qe, LambdaExpression exp, ref QueryProvider.NavigationSource source)
		{
			Expression expression = this.TranslateSelect(exp, qe, ref source);
			if (expression == null)
			{
				return null;
			}
			return this.MergeSubExpression(expression, methods, i);
		}
		private Expression TranslateSelect(LambdaExpression exp, QueryExpression qe, ref QueryProvider.NavigationSource source)
		{
			if (qe.Criteria.Conditions.Count != 1 || qe.Criteria.Conditions[0].Values.Count != 1 || !(qe.Criteria.Conditions[0].Values[0] is Guid))
			{
				return null;
			}
			ConditionExpression conditionExpression = qe.Criteria.Conditions[0];
			EntityReference target = new EntityReference(qe.EntityName, (Guid)conditionExpression.Values[0]);
			Relationship relationship;
			IQueryable selectRelationshipQuery = this.GetSelectRelationshipQuery(qe, exp, true, out relationship);
			if (selectRelationshipQuery != null)
			{
				source = new QueryProvider.NavigationSource(target, relationship);
				return selectRelationshipQuery.Expression;
			}
			source = null;
			return null;
		}
		private void TranslateSelect(QueryExpression qe, LambdaExpression exp, IEnumerable<QueryProvider.LinkLookup> linkLookups)
		{
			string parameterName = exp.Parameters[0].Name;
			foreach (QueryProvider.EntityColumn current in this.TraverseSelect(exp.Body))
			{
				if (linkLookups != null)
				{
					string expName = current.ParameterName;
					QueryProvider.LinkLookup linkLookup = linkLookups.SingleOrDefault((QueryProvider.LinkLookup l) => string.Format(CultureInfo.InvariantCulture, "{0}.{1}", new object[]
					{
						parameterName,
						l.Environment
					}) == expName);
					if (linkLookup != null && linkLookup.Link != null)
					{
						this.TranslateSelect(current, linkLookup.Link.Columns);
						continue;
					}
					if (linkLookup == null && exp.Parameters.Count > 1)
					{
						string name = exp.Parameters[1].Name;
						linkLookup = ((current.ParameterName == name) ? linkLookups.Last<QueryProvider.LinkLookup>() : ((current.ParameterName == parameterName && linkLookups.Count<QueryProvider.LinkLookup>() == 2) ? linkLookups.First<QueryProvider.LinkLookup>() : null));
						if (linkLookup != null && linkLookup.Link != null)
						{
							this.TranslateSelect(current, linkLookup.Link.Columns);
							continue;
						}
					}
				}
				this.TranslateSelect(current, qe.ColumnSet);
			}
		}
		private void TranslateSelect(QueryProvider.EntityColumn column, ColumnSet columnSet)
		{
			if (column.AllColumns)
			{
				columnSet.AllColumns = true;
				return;
			}
			if (!columnSet.AllColumns && !columnSet.Columns.Contains(column.Column))
			{
				columnSet.AddColumn(column.Column);
			}
		}
		private IEnumerable<QueryProvider.EntityColumn> TraverseSelect(Expression exp)
		{
			QueryProvider.EntityColumn entityColumn = this.TranslateSelectColumn(exp);
			if (entityColumn != null)
			{
				if (entityColumn.AllColumns || entityColumn.Column != null)
				{
					yield return entityColumn;
				}
			}
			else
			{
				foreach (Expression current in exp.GetChildren())
				{
					foreach (QueryProvider.EntityColumn current2 in this.TraverseSelect(current))
					{
						yield return current2;
					}
				}
			}
			yield break;
		}
		private QueryProvider.EntityColumn TranslateSelectColumn(Expression exp)
		{
			MemberExpression memberExpression = exp as MemberExpression;
			MethodCallExpression methodCallExpression = exp as MethodCallExpression;
			ParameterExpression pe = exp as ParameterExpression;
			if ((memberExpression != null && memberExpression.Expression != null && this.IsEntity(memberExpression.Expression.Type)) || (methodCallExpression != null && methodCallExpression.Object != null && this.IsEntity(methodCallExpression.Object.Type)))
			{
				if (memberExpression != null && memberExpression.Member.DeclaringType == typeof(Entity))
				{
					return new QueryProvider.EntityColumn();
				}
				string text = null;
				string text2 = this.TranslateExpressionToAttributeName(exp, true, out text);
				if (!string.IsNullOrEmpty(text2))
				{
					string underlyingParameterExpressionName = this.GetUnderlyingParameterExpressionName(exp);
					return new QueryProvider.EntityColumn(underlyingParameterExpressionName, text2);
				}
			}
			else
			{
				if ((memberExpression != null && this.IsEntity(memberExpression.Type)) || (methodCallExpression != null && this.IsEntity(methodCallExpression.Type)))
				{
					string parameterName = exp.ToString();
					return new QueryProvider.EntityColumn(parameterName, true);
				}
				if ((memberExpression != null && this.IsEnumerableEntity(memberExpression.Type)) || (methodCallExpression != null && this.IsEnumerableEntity(methodCallExpression.Type)))
				{
					this.ThrowException(new NotSupportedException(string.Format(CultureInfo.InvariantCulture, "The expression '{0}' is an invalid column projection expression. Entity collections cannot be selected.", new object[]
					{
						exp
					})));
				}
			}
			return this.TranslateSelectColumn(pe);
		}
		protected virtual QueryProvider.EntityColumn TranslateSelectColumn(ParameterExpression pe)
		{
			if (pe != null && this.IsEntity(pe.Type))
			{
				string parameterName = pe.ToString();
				return new QueryProvider.EntityColumn(parameterName, true);
			}
			if (pe != null && this.IsEnumerableEntity(pe.Type))
			{
				this.ThrowException(new NotSupportedException(string.Format(CultureInfo.InvariantCulture, "The expression '{0}' is an invalid column projection expression. Entity collections cannot be selected.", new object[]
				{
					pe
				})));
			}
			return null;
		}
		private Expression TranslateSelectMany(IList<MethodCallExpression> methods, int i, QueryExpression qe, LambdaExpression exp, ref QueryProvider.NavigationSource source)
		{
			Expression expression = this.TranslateSelectMany(qe, exp, ref source);
			if (expression == null)
			{
				return null;
			}
			return this.MergeSubExpression(expression, methods, i);
		}
		private Expression MergeSubExpression(Expression subExpression, IList<MethodCallExpression> methods, int i)
		{
			for (int j = i + 1; j < methods.Count; j++)
			{
				MethodCallExpression methodCallExpression = methods[j];
				subExpression = Expression.Call(null, methodCallExpression.Method, new Expression[]
				{
					subExpression
				}.Concat(methodCallExpression.Arguments.Skip(1)));
			}
			return subExpression;
		}
		private Expression TranslateSelectMany(QueryExpression qe, LambdaExpression exp, ref QueryProvider.NavigationSource source)
		{
			if (qe.Criteria.Conditions.Count != 1 || qe.Criteria.Conditions[0].Values.Count != 1 || !(qe.Criteria.Conditions[0].Values[0] is Guid))
			{
				this.ThrowException(new InvalidOperationException("A 'SelectMany' operation must be preceeded by a 'Where' operation that filters by an entity ID."));
			}
			ConditionExpression conditionExpression = qe.Criteria.Conditions[0];
			EntityReference target = new EntityReference(qe.EntityName, (Guid)conditionExpression.Values[0]);
			Relationship relationship = null;
			IQueryable selectRelationshipQuery = this.GetSelectRelationshipQuery(qe, exp, false, out relationship);
			if (selectRelationshipQuery != null)
			{
				source = new QueryProvider.NavigationSource(target, relationship);
				return selectRelationshipQuery.Expression;
			}
			source = null;
			return null;
		}
		protected virtual IQueryable GetSelectRelationshipQuery(QueryExpression qe, LambdaExpression exp, bool isSelect, out Relationship relationship)
		{
			MemberExpression memberExpression = this.FindEntityExpression(exp.Body) as MemberExpression;
			if (memberExpression == null)
			{
				relationship = null;
				return null;
			}
			RelationshipSchemaNameAttribute firstOrDefaultCustomAttribute = memberExpression.Member.GetFirstOrDefaultCustomAttribute<RelationshipSchemaNameAttribute>();
			if (firstOrDefaultCustomAttribute == null)
			{
				if (isSelect)
				{
					relationship = null;
					return null;
				}
				this.ThrowException(new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "The relationship property '{0}' is invalid.", new object[]
				{
					memberExpression.Member.Name
				})));
			}
			relationship = firstOrDefaultCustomAttribute.Relationship;
			Type entityType = isSelect ? memberExpression.Type : memberExpression.Type.GetGenericArguments()[0];
			return this.CreateQuery(entityType);
		}
		private Expression GetMethodCallBody(MethodCallExpression mce, out string parameterName)
		{
			if (mce.Arguments.Count <= 1)
			{
				parameterName = null;
				return null;
			}
			LambdaExpression lambdaExpression = (mce.Arguments[1] as UnaryExpression).Operand as LambdaExpression;
			parameterName = lambdaExpression.Parameters[0].Name;
			return lambdaExpression.Body;
		}
		protected virtual string TranslateExpressionToAttributeName(Expression exp, bool isSelectExpression, out string alias)
		{
			alias = null;
			MethodCallExpression methodCallExpression = exp as MethodCallExpression;
			if (methodCallExpression != null)
			{
				Expression exp2 = methodCallExpression.Method.IsStatic ? methodCallExpression.Arguments.Skip(1).First<Expression>() : methodCallExpression.Arguments.First<Expression>();
				return this.TranslateExpressionToValue(exp2, new ParameterExpression[0]) as string;
			}
			MemberExpression memberExpression = exp as MemberExpression;
			if (memberExpression != null && memberExpression.Member != null)
			{
				MemberExpression memberExpression2 = memberExpression.Expression as MemberExpression;
				ParameterExpression parameterExpression = memberExpression.Expression as ParameterExpression;
				if (memberExpression2 != null)
				{
					AttributeLogicalNameAttribute firstOrDefaultCustomAttribute = memberExpression2.Member.GetFirstOrDefaultCustomAttribute<AttributeLogicalNameAttribute>();
					if (firstOrDefaultCustomAttribute != null)
					{
						return firstOrDefaultCustomAttribute.LogicalName;
					}
				}
				else if (parameterExpression != null && memberExpression.Member.Name == "Id" && this.IsStaticEntity(parameterExpression.Type))
				{
					PropertyInfo property = parameterExpression.Type.GetProperty("Id");
					AttributeLogicalNameAttribute firstOrDefaultCustomAttribute2 = property.GetFirstOrDefaultCustomAttribute<AttributeLogicalNameAttribute>();
					if (firstOrDefaultCustomAttribute2 != null)
					{
						return firstOrDefaultCustomAttribute2.LogicalName;
					}
				}
				return memberExpression.Member.GetLogicalName();
			}
			this.ThrowException(new InvalidOperationException("Cannot determine the attribute name."));
			return null;
		}
		protected virtual bool IsEnumerableEntity(Type type)
		{
			if (!type.IsGenericType)
			{
				return false;
			}
			if (type.GetGenericTypeDefinition() != typeof(IEnumerable<>))
			{
				return false;
			}
			Type[] genericArguments = type.GetGenericArguments();
			return genericArguments.Length == 1 && this.IsEntity(genericArguments[0]);
		}
		private static bool IsAnonymousType(Type type)
		{
			bool flag = type.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Count<object>() > 0;
			bool flag2 = type.FullName.Contains("AnonymousType");
			return flag && flag2;
		}
		protected virtual bool IsEntity(Type type)
		{
			return this.IsDynamicEntity(type) || this.IsStaticEntity(type);
		}
		protected virtual bool IsDynamicEntity(Type type)
		{
			return type.IsA<Entity>();
		}
		private bool IsStaticEntity(Type type)
		{
			string logicalName = type.GetLogicalName();
			return logicalName != null;
		}
		protected virtual Expression FindValidEntityExpression(Expression exp, string operation = "where")
		{
			UnaryExpression unaryExpression = exp as UnaryExpression;
			if (unaryExpression != null && (unaryExpression.NodeType == ExpressionType.Convert || unaryExpression.NodeType == ExpressionType.TypeAs))
			{
				return this.FindValidEntityExpression(unaryExpression.Operand, operation);
			}
			NewExpression newExpression = exp as NewExpression;
			if (newExpression != null && newExpression.Type == typeof(EntityReference) && newExpression.Arguments.Count >= 2)
			{
				return this.FindValidEntityExpression(newExpression.Arguments[1], operation);
			}
			if (this.IsEntityExpression(exp))
			{
				return exp;
			}
			MemberExpression memberExpression = exp as MemberExpression;
			if (memberExpression != null && QueryProvider._validProperties.Contains(memberExpression.Member.Name))
			{
				return this.FindValidEntityExpression(memberExpression.Expression, operation);
			}
			MethodCallExpression methodCallExpression = exp as MethodCallExpression;
			if (methodCallExpression != null && QueryProvider._validMethods.Contains(methodCallExpression.Method.Name))
			{
				return this.FindValidEntityExpression(methodCallExpression.Object, operation);
			}
			this.ThrowException(new NotSupportedException(string.Format(CultureInfo.InvariantCulture, "Invalid '{0}' condition. An entity member is invoking an invalid property or method.", new object[]
			{
				operation
			})));
			return null;
		}
		protected Expression FindEntityExpression(Expression exp)
		{
			return exp.FindPreorder(new Predicate<Expression>(this.IsEntityExpression));
		}
		protected virtual bool IsEntityExpression(Expression e)
		{
			MemberExpression memberExpression = e as MemberExpression;
			MethodCallExpression methodCallExpression = e as MethodCallExpression;
			if (methodCallExpression != null)
			{
				if (methodCallExpression.Object != null)
				{
					return this.IsDynamicEntity(methodCallExpression.Object.Type);
				}
				if (methodCallExpression.Method.IsStatic)
				{
					return this.IsDynamicEntity(methodCallExpression.Arguments[0].Type);
				}
			}
			else if (memberExpression != null)
			{
				return this.IsEntityMemberExpression(memberExpression);
			}
			return false;
		}
		protected virtual bool IsEntityMemberExpression(MemberExpression me)
		{
			return me.Member != null && this.IsEntity(me.Member.DeclaringType);
		}
		private MemberExpression GetUnderlyingMemberExpression(Expression exp)
		{
			MemberExpression memberExpression = exp as MemberExpression;
			MethodCallExpression methodCallExpression = exp as MethodCallExpression;
			if (memberExpression != null)
			{
				return memberExpression.Expression as MemberExpression;
			}
			if (methodCallExpression != null)
			{
				return methodCallExpression.Object as MemberExpression;
			}
			this.ThrowException(new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "The expression '{0}' must be a '{1}' or a '{2}'.", new object[]
			{
				exp,
				typeof(MemberExpression),
				typeof(MethodCallExpression)
			})));
			return null;
		}
		private string GetUnderlyingParameterExpressionName(Expression exp)
		{
			MemberExpression memberExpression = exp as MemberExpression;
			MethodCallExpression methodCallExpression = exp as MethodCallExpression;
			if (memberExpression != null)
			{
				return memberExpression.Expression.ToString();
			}
			if (methodCallExpression != null)
			{
				return methodCallExpression.Object.ToString();
			}
			this.ThrowException(new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "The expression '{0}' must be a '{1}' or a '{2}'.", new object[]
			{
				exp,
				typeof(MemberExpression),
				typeof(MethodCallExpression)
			})));
			return null;
		}
		private object TranslateExpressionToValue(Expression exp, params ParameterExpression[] parameters)
		{
			ConstantExpression constantExpression = exp as ConstantExpression;
			if (constantExpression != null)
			{
				return constantExpression.Value;
			}
			MemberExpression memberExpression = exp as MemberExpression;
			if (memberExpression != null)
			{
				ConstantExpression constantExpression2 = memberExpression.Expression as ConstantExpression;
				if (constantExpression2 != null)
				{
					object value = constantExpression2.Value;
					FieldInfo fieldInfo = memberExpression.Member as FieldInfo;
					if (fieldInfo != null)
					{
						return this.GetFieldValue(fieldInfo, value);
					}
					PropertyInfo propertyInfo = memberExpression.Member as PropertyInfo;
					if (propertyInfo != null)
					{
						return this.GetPropertyValue(propertyInfo, value);
					}
				}
			}
			UnaryExpression unaryExpression = exp as UnaryExpression;
			if (unaryExpression != null && unaryExpression.NodeType == ExpressionType.Convert)
			{
				return this.TranslateExpressionToValue(unaryExpression.Operand, new ParameterExpression[0]);
			}
			LambdaExpression expression = Expression.Lambda(exp, parameters);
			Delegate project = this.CompileExpression(expression);
			return this.DynamicInvoke(project, new object[0]);
		}
		[SecuritySafeCritical]
		private object GetFieldValue(FieldInfo fieldInfo, object target)
		{
			object value;
			try
			{
				new ReflectionPermission(ReflectionPermissionFlag.RestrictedMemberAccess).Assert();
				value = fieldInfo.GetValue(target);
			}
			finally
			{
				CodeAccessPermission.RevertAssert();
			}
			return value;
		}
		[SecuritySafeCritical]
		private object GetPropertyValue(PropertyInfo propertyInfo, object target)
		{
			object value;
			try
			{
				new ReflectionPermission(ReflectionPermissionFlag.RestrictedMemberAccess).Assert();
				value = propertyInfo.GetValue(target, null);
			}
			finally
			{
				CodeAccessPermission.RevertAssert();
			}
			return value;
		}
		private object TranslateExpressionToConditionValue(Expression exp, params ParameterExpression[] parameters)
		{
			object obj = this.TranslateExpressionToValue(exp, parameters);
			EntityReference entityReference = obj as EntityReference;
			OptionSetValue optionSetValue = obj as OptionSetValue;
			Money money = obj as Money;
			if (obj is DateTime)
			{
				obj = ((DateTime)obj).ToString("u", CultureInfo.InvariantCulture);
			}
			else if (entityReference != null)
			{
				obj = entityReference.Id;
			}
			else if (money != null)
			{
				obj = money.Value;
			}
			else if (optionSetValue != null)
			{
				obj = optionSetValue.Value;
			}
			else if (obj != null && obj.GetType().IsEnum)
			{
				obj = (int)obj;
			}
			return obj;
		}
		protected virtual void TranslateEntityName(QueryExpression qe, Expression expression, MethodCallExpression mce)
		{
			if (qe.EntityName == null)
			{
				ConstantExpression constantExpression = (expression is MethodCallExpression) ? (expression.GetMethodsPreorder().Last<MethodCallExpression>().Arguments[0] as ConstantExpression) : (expression as ConstantExpression);
				if (constantExpression != null)
				{
					IEntityQuery entityQuery = constantExpression.Value as IEntityQuery;
					if (entityQuery != null)
					{
						qe.EntityName = entityQuery.EntityLogicalName;
					}
				}
			}
		}
		protected virtual void ThrowException(Exception exception)
		{
			throw exception;
		}
		static QueryProvider()
		{
			// Note: this type is marked as 'beforefieldinit'.
			string[] followingRoot = new string[1];
			QueryProvider._followingRoot = followingRoot;
			QueryProvider._followingFirst = QueryProvider._followingRoot.Concat(new string[]
			{
				"ToList"
			});
			QueryProvider._followingTake = QueryProvider._followingFirst.Concat(new string[]
			{
				"Select",
				"First",
				"FirstOrDefault",
				"Single",
				"SingleOrDefault",
				"Distinct"
			});
			QueryProvider._followingSkip = QueryProvider._followingTake.Concat(new string[]
			{
				"Take"
			});
			QueryProvider._followingSelect = QueryProvider._followingSkip.Concat(new string[]
			{
				"Skip"
			});
			QueryProvider._followingOrderBy = QueryProvider._followingSelect.Concat(new string[]
			{
				"Select",
				"Where",
				"OrderBy",
				"OrderByDescending",
				"ThenBy",
				"ThenByDescending"
			});
			QueryProvider._followingWhere = QueryProvider._followingOrderBy.Concat(new string[]
			{
				"SelectMany"
			});
			QueryProvider._followingJoin = QueryProvider._followingWhere.Concat(new string[]
			{
				"Join"
			});
			QueryProvider._followingGroupJoin = QueryProvider._followingRoot.Concat(new string[]
			{
				"SelectMany"
			});
			QueryProvider._followingMethodLookup = new Dictionary<string, IEnumerable<string>>
			{

				{
					"Join",
					QueryProvider._followingJoin
				},

				{
					"GroupJoin",
					QueryProvider._followingGroupJoin
				},

				{
					"Where",
					QueryProvider._followingWhere
				},

				{
					"OrderBy",
					QueryProvider._followingOrderBy
				},

				{
					"OrderByDescending",
					QueryProvider._followingOrderBy
				},

				{
					"ThenBy",
					QueryProvider._followingOrderBy
				},

				{
					"ThenByDescending",
					QueryProvider._followingOrderBy
				},

				{
					"Select",
					QueryProvider._followingSelect
				},

				{
					"Skip",
					QueryProvider._followingSkip
				},

				{
					"Take",
					QueryProvider._followingTake
				},

				{
					"First",
					QueryProvider._followingFirst
				},

				{
					"FirstOrDefault",
					QueryProvider._followingFirst
				},

				{
					"Single",
					QueryProvider._followingFirst
				},

				{
					"SingleOrDefault",
					QueryProvider._followingFirst
				},

				{
					"SelectMany",
					QueryProvider._followingOrderBy
				},

				{
					"Distinct",
					QueryProvider._followingSkip
				},

				{
					"Cast",
					new string[]
					{
						"Select"
					}
				}
			};
			QueryProvider._supportedMethods = new string[]
			{
				"Equals",
				"Contains",
				"StartsWith",
				"EndsWith"
			};
			QueryProvider._validMethods = QueryProvider._supportedMethods.Concat(new string[]
			{
				"Compare",
				"Like",
				"GetValueOrDefault"
			}).ToArray<string>();
			QueryProvider._validProperties = new string[]
			{
				"Id",
				"Value"
			};
			QueryProvider._conditionLookup = new Dictionary<ExpressionType, ConditionOperator>
			{

				{
					ExpressionType.Equal,
					ConditionOperator.Equal
				},

				{
					ExpressionType.GreaterThan,
					ConditionOperator.GreaterThan
				},

				{
					ExpressionType.GreaterThanOrEqual,
					ConditionOperator.GreaterEqual
				},

				{
					ExpressionType.LessThan,
					ConditionOperator.LessThan
				},

				{
					ExpressionType.LessThanOrEqual,
					ConditionOperator.LessEqual
				},

				{
					ExpressionType.NotEqual,
					ConditionOperator.NotEqual
				}
			};
			QueryProvider._operatorNegationLookup = new Dictionary<ConditionOperator, ConditionOperator>
			{

				{
					ConditionOperator.Equal,
					ConditionOperator.NotEqual
				},

				{
					ConditionOperator.NotEqual,
					ConditionOperator.Equal
				},

				{
					ConditionOperator.GreaterThan,
					ConditionOperator.LessEqual
				},

				{
					ConditionOperator.GreaterEqual,
					ConditionOperator.LessThan
				},

				{
					ConditionOperator.LessThan,
					ConditionOperator.GreaterEqual
				},

				{
					ConditionOperator.LessEqual,
					ConditionOperator.GreaterThan
				},

				{
					ConditionOperator.Like,
					ConditionOperator.NotLike
				},

				{
					ConditionOperator.NotLike,
					ConditionOperator.Like
				},

				{
					ConditionOperator.Null,
					ConditionOperator.NotNull
				},

				{
					ConditionOperator.NotNull,
					ConditionOperator.Null
				}
			};
			QueryProvider._booleanLookup = new Dictionary<ExpressionType, LogicalOperator>
			{

				{
					ExpressionType.And,
					LogicalOperator.And
				},

				{
					ExpressionType.Or,
					LogicalOperator.Or
				},

				{
					ExpressionType.AndAlso,
					LogicalOperator.And
				},

				{
					ExpressionType.OrElse,
					LogicalOperator.Or
				}
			};
			QueryProvider._logicalOperatorNegationLookup = new Dictionary<LogicalOperator, LogicalOperator>
			{

				{
					LogicalOperator.And,
					LogicalOperator.Or
				},

				{
					LogicalOperator.Or,
					LogicalOperator.And
				}
			};
		}
	}
}
